package com.whfc.openapi.api.emp.service;

import com.whfc.common.enums.BindFlag;
import com.whfc.common.enums.FenceType;
import com.whfc.common.exception.BizException;
import com.whfc.common.geometry.GeometryUtil;
import com.whfc.common.geometry.Point;
import com.whfc.common.geometry.Polygon;
import com.whfc.common.result.ListData;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.DateUtil;
import com.whfc.emp.dto.*;
import com.whfc.emp.dto.openapi.*;
import com.whfc.emp.enums.AppWorkRole;
import com.whfc.emp.enums.AttendType;
import com.whfc.emp.param.*;
import com.whfc.emp.param.openapi.*;
import com.whfc.emp.service.*;
import com.whfc.entity.dto.emp.AttendStatDTO;
import com.whfc.uni.enums.Direction;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author sun_guodong
 * @description
 * @date 2020-06-22
 */
@Service
public class OpenApiEmpServiceImpl implements OpenApiEmpService {

    @DubboReference(interfaceClass = AppEmpService.class, version = "1.0.0")
    private AppEmpService appEmpService;

    @DubboReference(interfaceClass = AppFenceService.class, version = "1.0.0")
    private AppFenceService appFenceService;

    @DubboReference(interfaceClass = AppEmpDayService.class, version = "1.0.0")
    private AppEmpDayService appEmpDayService;

    @DubboReference(interfaceClass = AppEmpAttendService.class, version = "1.0.0")
    private AppEmpAttendService appEmpAttendService;

    @DubboReference(interfaceClass = AppEmpWarnService.class, version = "1.0.0")
    private AppEmpWarnService appEmpWarnService;

    @DubboReference(interfaceClass = AppEmpInputDataService.class, version = "1.0.0")
    private AppEmpInputDataService appEmpInputDataService;

    @DubboReference(interfaceClass = AppGroupService.class, version = "1.0.0")
    private AppGroupService appGroupService;


    @Override
    public PageData<OpenApiEmpDTO> list(Integer deptId, Integer pageNum, Integer pageSize) {
        return appEmpService.listOpenApiEmp(deptId, pageNum, pageSize);
    }

    @Override
    public OpenApiEmpDTO detail(Integer empId) {
        return appEmpService.getOpenApiEmpDetail(empId);
    }

    @Override
    public OpenApiEmpDTO add(OpenApiAddEmpParam param) {
        AppEmpAddParam appEmpAddParam = new AppEmpAddParam();
        BeanUtils.copyProperties(param, appEmpAddParam);
        Integer empId = appEmpService.addEmp(appEmpAddParam);

        OpenApiEmpDTO data = new OpenApiEmpDTO();
        data.setEmpId(empId);
        data.setEmpName(param.getEmpName());
        data.setGender(param.getGender());
        data.setPhone(param.getPhone());
        return data;
    }

    @Override
    public void edit(OpenApiEditEmpParam param) {
        AppEmpEditParam appEmpEditParam = new AppEmpEditParam();
        BeanUtils.copyProperties(param, appEmpEditParam);
        appEmpService.edit(appEmpEditParam);
    }

    @Override
    public void del(Integer empId) {
        appEmpService.del(empId);
    }

    @Override
    public void bind(OpenApiBindEmpParam param) {
        AppEmpDeviceBindParam request = new AppEmpDeviceBindParam();
        request.setEmpId(param.getEmpId());
        request.setSn(param.getDeviceSn());
        appEmpService.bind(null, null, request);
    }

    @Override
    public void unbind(OpenApiBindEmpParam param) {
        AppEmpDTO appEmp = appEmpService.getEmpInfo(param.getEmpId());
        if (appEmp == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "未找到该人员信息");
        }
        if (!param.getDeviceSn().equals(appEmp.getSn())) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该人员绑定信息错误");
        }

        AppEmpDeviceUnbindParam request = new AppEmpDeviceUnbindParam();
        request.setEmpId(param.getEmpId());
        appEmpService.unbind(null, null, request);
    }

    @Override
    public OpenApiEmpDTO deviceData(Integer empId) {
        OpenApiEmpDTO empDetail = appEmpService.getOpenApiEmpDetail(empId);
        if (empDetail == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "未找到该人员信息");
        }
        if (BindFlag.UNBIND.getValue().equals(empDetail.getBindFlag())) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该人员未绑定安全帽");
        }
        return empDetail;
    }

    @Override
    public void enter(OpenApiEmpEnterParam param) {
        AppEmpEnterParam request = new AppEmpEnterParam();
        request.setDate(param.getDate());
        request.setEmpId(param.getEmpId());
        appEmpService.enter(request);
    }

    @Override
    public void outer(OpenApiEmpEnterParam param) {
        AppEmpOuterParam request = new AppEmpOuterParam();
        request.setDate(param.getDate());
        request.setEmpId(param.getEmpId());
        appEmpService.outer(request);
    }

    @Override
    public ListData<OpenApiFenceDTO> fenceList(Integer deptId) {
        AppFenceListParam request = new AppFenceListParam();
        request.setDeptId(deptId);
        List<AppFenceDTO> appFenceList = appFenceService.list(request);

        List<OpenApiFenceDTO> list = new ArrayList<>();
        for (AppFenceDTO appFenceDTO : appFenceList) {
            Integer type = appFenceDTO.getType();
            OpenApiFenceDTO openApiFenceDTO = new OpenApiFenceDTO();
            openApiFenceDTO.setType(type);
            openApiFenceDTO.setFenceId(appFenceDTO.getId());
            openApiFenceDTO.setFenceName(appFenceDTO.getName());

            if (FenceType.CIRCLE.value().equals(type)) {
                Point point = GeometryUtil.decodePoint(appFenceDTO.getCenter());
                openApiFenceDTO.setCenter(point);
                openApiFenceDTO.setRadius(appFenceDTO.getRadius());
            } else if (FenceType.POLYGON.value().equals(type)) {
                Polygon polygon = GeometryUtil.decodePolygon(appFenceDTO.getPolygon());
                openApiFenceDTO.setPolygon(polygon);
            }
            list.add(openApiFenceDTO);
        }
        return new ListData<>(list);
    }

    @Override
    public OpenApiFenceDTO fenceAdd(OpenApiFenceAddParam param) {
        Double radius = param.getRadius();
        String fenceName = param.getFenceName();
        Integer type = param.getType();
        Point center = param.getCenter();
        List<Point> pointList = param.getPolygon();

        AppFenceAddParam request = new AppFenceAddParam();
        request.setRadius(radius);
        request.setType(type);
        request.setName(fenceName);
        request.setDeptId(param.getDeptId());
        request.setCenterPoint(center);
        request.setPolygonPointList(pointList);
        Integer fenceId = appFenceService.add(request);

        OpenApiFenceDTO data = new OpenApiFenceDTO();
        data.setRadius(radius);
        data.setFenceName(fenceName);
        data.setFenceId(fenceId);
        data.setType(type);
        data.setCenter(center);
        Polygon polygon = new Polygon();
        polygon.setPointList(pointList);
        data.setPolygon(polygon);
        return data;
    }

    @Override
    public void fenceEdit(OpenApiFenceEditParam param) {
        AppFenceAddParam request = new AppFenceAddParam();
        request.setRadius(param.getRadius());
        request.setType(param.getType());
        request.setName(param.getFenceName());
        request.setCenterPoint(param.getCenter());
        request.setPolygonPointList(param.getPolygon());
        request.setId(param.getFenceId());
        appFenceService.add(request);
    }

    @Override
    public void fenceDel(Integer fenceId) {
        appFenceService.del(fenceId);
    }

    @Override
    public void fenceInvoke(OpenApiFenceInvokeParam param) {
        AppFenceEmpAddParam request = new AppFenceEmpAddParam();
        request.setFenceId(param.getFenceId());
        request.setEmpList(param.getEmpIdList());
        appFenceService.addEmp(request);
    }

    @Override
    public void fenceRevoke(OpenApiFenceInvokeParam param) {
        List<Integer> empIdList = param.getEmpIdList();
        Integer fenceId = param.getFenceId();
        for (Integer empId : empIdList) {
            AppFenceEmpDelParam request = new AppFenceEmpDelParam();
            request.setEmpId(empId);
            request.setFenceId(fenceId);
            appFenceService.delEmp(request);
        }
    }


    @Override
    public OpenApiEmpAttendDayDTO attendDay(Integer empId, Date date) {
        return appEmpDayService.getOpenApiAttendDay(empId, date);
    }

    @Override
    public ListData<AppEmpAttendRecordDTO> attendRecord(Integer empId, Date date) {
        List<AppEmpAttendRecordDTO> list = appEmpAttendService.attendRecord(empId, date, null);
        return new ListData<>(list);
    }

    @Override
    public ListData<AppEmpGpsDTO> gps(Integer empId, Date date) {
        List<AppEmpGpsDTO> list = appEmpService.getGpsList(empId, date);
        return new ListData<>(list);
    }

    @Override
    public ListData<OpenApiEmpWarnDTO> warnList(Integer empId, Date date) {
        List<OpenApiEmpWarnDTO> list = appEmpWarnService.getOpenApiEmpWarnList(empId, date);
        return new ListData<>(list);
    }

    @Override
    public WxEmpCurveMapDTO getMultiEmpCurveData(Integer deptId) {
        /*// 指定机构->人员列表
        Collection<Integer> deptIds = new ArrayList<>();
        deptIds.add(deptId);
        int totalEmpNum = 0;
        int attendEmpNum = 0;
        int absenceEmpNum = 0;
        int localeEmpNum = 0;
        int outLocaleEmpNum = 0;
        int onlineEmpNum = 0;
        int offlineEmpNum = 0;

        List<WxEmpCurveMapDayDTO> dayList = Collections.emptyList();
        List<WxEmpCurveMapMonthDTO> monthList = Collections.emptyList();
        double avgDayAttendEmpNum = 0;
        double avgDayWarnCnt = 0;
        double avgDayWorkTimes = 0;
        double avgMonthDays = 0;

        //当前人员统计
        totalEmpNum = appEmpMapper.countTotalEmpNumInDept(deptIds, null, null, null);
        attendEmpNum = appEmpMapper.countTotalEmpNumInDeptByAttendState(deptIds, AttendState.ATTEND.getValue(), null, null, null);
        absenceEmpNum = totalEmpNum - attendEmpNum;
        localeEmpNum = appEmpMapper.countLocaleEmpNumInDeptByLocaleState(deptIds, LocaleState.IN.getValue(), null, null, null);
        outLocaleEmpNum = attendEmpNum - localeEmpNum;
        onlineEmpNum = appEmpMapper.countTotalEmpNumInDeptByNetState(deptIds, NetState.ONLINE.getValue(), null, null, null);
        offlineEmpNum = totalEmpNum - onlineEmpNum;
        //过去7天的数据统计
        int days = 7;
        Date now = new Date();
        Date today = DateUtil.getDateBegin(now);
        Date startDate = DateUtil.addDays(today, -days);
        Date endDate = DateUtil.addDays(today, -1);
        dayList = appEmpDayMapper.selectWxEmpCurveMapDayDTOListInDept(deptIds, startDate, endDate, null, null, null);

        int totalAttendEmpNum = 0;
        int totalWorkTimes = 0;
        int totalWarnCnt = 0;
        for (WxEmpCurveMapDayDTO dayDTO : dayList) {
            totalAttendEmpNum += dayDTO.getAttendEmpNum();
            totalWorkTimes += dayDTO.getWorkTimes();
            totalWarnCnt += dayDTO.getWarnCnt();
        }
        if (dayList.size() > 0) {
            avgDayAttendEmpNum = MathUtil.round((double) totalAttendEmpNum / (dayList.size()), 2);
        }
        if (totalAttendEmpNum > 0) {
            avgDayWarnCnt = MathUtil.round((double) totalWarnCnt / totalAttendEmpNum, 2);
            avgDayWorkTimes = MathUtil.round((double) totalWorkTimes / totalAttendEmpNum, 2);
        }

        //过去3个月统计
        int months = 3;
        Date month = DateUtil.getMonthBegin(now);
        Date startMonth = DateUtil.addMonth(month, -months);
        Date endMonth = month;

        int totalMonthDays = 0;
        monthList = appEmpDayMapper.selectWxEmpCurveMonthDTOListInDept(deptIds, startMonth, endMonth, null, null, null);
        for (WxEmpCurveMapMonthDTO monthDTO : monthList) {
            totalMonthDays += monthDTO.getDays();
        }
        if (monthList.size() > 0) {
            avgMonthDays = MathUtil.round((double) totalMonthDays / (monthList.size()), 2);
        }


        WxEmpCurveMapDTO curveMapDTO = new WxEmpCurveMapDTO();
        curveMapDTO.setTotalEmpNum(totalEmpNum);
        curveMapDTO.setAttendEmpNum(attendEmpNum);
        curveMapDTO.setAbsenceEmpNum(absenceEmpNum);
        curveMapDTO.setAvgDayAttendEmpNum(avgDayAttendEmpNum);
        curveMapDTO.setAvgDayWarnCnt(avgDayWarnCnt);
        curveMapDTO.setAvgDayWorkTimes(avgDayWorkTimes);
        curveMapDTO.setDayList(dayList);
        curveMapDTO.setAvgMonthDays(avgMonthDays);
        curveMapDTO.setMonthList(monthList);
        curveMapDTO.setLocaleEmpNum(localeEmpNum);
        curveMapDTO.setOutLocaleEmpNum(outLocaleEmpNum);
        curveMapDTO.setOnlineEmpNum(onlineEmpNum);
        curveMapDTO.setOfflineEmpNum(offlineEmpNum);
        return curveMapDTO;*/
        return null;
    }

    @Override
    public List<StatItem> adsqStatistics(Integer deptId) {
        //管理人员
        int managerNum = appEmpService.countByWorkRole(deptId, AppWorkRole.MANAGER);
        int workerNum = appEmpService.countByWorkRole(deptId, AppWorkRole.WORKER);

        StatItem item1 = new StatItem();
        item1.setType(AppWorkRole.MANAGER.getDesc());
        item1.setValue(managerNum);

        StatItem item2 = new StatItem();
        item2.setType(AppWorkRole.WORKER.getDesc());
        item2.setValue(workerNum);

        return Arrays.asList(item1, item2);
    }

    @Override
    public List<StatItem> adsqLocaleInEmpNum(Integer deptId) {
        int localeInEmpNum = appEmpService.countLocaleEmpNum(deptId);
        StatItem item = new StatItem();
        item.setValue(localeInEmpNum);
        return Collections.singletonList(item);
    }

    @Override
    public AttendStatDTO adsqFaceGateStatistics(Integer deptId, Date date) {
        if (date == null) {
            date = new Date();
        }
        Date startTime = DateUtil.getDateBegin(date);
        Date endTime = DateUtil.getDateEnd(date);

        List<Integer> attendTypes = Collections.singletonList(AttendType.FACEGATE.getValue());
        List<AppEmpAttendRecordDTO> attendRecordDTOList = appEmpAttendService.attendRecord(deptId, startTime, endTime, AttendType.FACEGATE);
        //进出人次
        int inCount = 0;
        int outCount = 0;

        //出勤人数
        Map<Integer, Integer> attendMap = new HashMap<>(attendRecordDTOList.size());

        //在场人数
        Map<Integer, Integer> localeMap = new HashMap<>(attendRecordDTOList.size());

        for (AppEmpAttendRecordDTO dto : attendRecordDTOList) {
            //进
            if (Direction.IN.getValue().equals(dto.getDirection())) {
                inCount++;
                localeMap.put(dto.getEmpId(), dto.getEmpId());
                attendMap.put(dto.getEmpId(), dto.getEmpId());
            }
            //出
            else if (Direction.OUT.getValue().equals(dto.getDirection())) {
                outCount++;
                localeMap.remove(dto.getEmpId());
            }
        }


        AttendStatDTO statDTO = new AttendStatDTO();
        statDTO.setAttendNum(attendMap.size());
        statDTO.setLocaleInNum(localeMap.size());
        statDTO.setInCount(inCount);
        statDTO.setOutCount(outCount);
        return statDTO;
    }
}
